package model;

import model.exception.MacAddressException;

/**
 * <b>Ebtables</b> is an application program used to set up and maintain the tables of rules (inside the Linux kernel) that inspect Ethernet frames. It is analogous to the iptables application, but less complicated, due to the fact that the Ethernet protocol is much simpler than the IP protocol.
 * 
 * @author Dumella De Rosa Gennaro
 */
public class Ebtables {
	
	/**
	 * As stated earlier, there are three ebtables tables in the Linux kernel. The table names are {@link Table#filter}, {@link Table#nat} and {@link Table#broute}. Of these three tables, the filter table is the default table that the command operates on. If you are working with the filter table, then you can drop the '-t filter' argument to the ebtables command. However, you will need to provide the -t argument for the other two tables. Moreover, the -t argument must be the first argument on the ebtables command line, if used. 
	 * 
	 * @author Dumella De Rosa Gennaro
	 */
	public static enum Table{
		/**
		 *	<b>filter</b> is the default table and contains three built-in chains: INPUT,OUTPUT and FORWARD. 
		 */
		filter,
		/**
		 *	<b>nat</b> is mostly used to change the mac addresses and contains three built-in chains: PREROUTING, OUTPUT and POSTROUTING. A small note on the naming of chains PREROUTING and POSTROUTING: it would be more accurate to call them PREFORWARDING and POSTFORWARDING, but for all those who come from the iptables world to ebtables it is easier to have the same names.
		 */
		nat,
		/**
		 *	<b>broute</b> is used to make a brouter, it has one built-in chain: BROUTING. The targets DROP and ACCEPT have a special meaning in the broute table (these names are used instead of more descriptive names to keep the implementation generic). DROP actually means the frame has to be routed, while ACCEPT means the frame has to be bridged. The BROUTING chain is traversed very early. However, it is only traversed by frames entering on a bridge port that is in forwarding state. Normally those frames would be bridged, but you can decide otherwise here. The redirect target is very handy here. 
		 */
		broute
	};
	/**
	 * The ebtables command arguments specify the actions to perform on the table defined with the -t argument. Only one command may be used on the command line at a time. The commands are: {@link Action#A} ,{@link Action#C}, {@link Action#D}, {@link Action#I}.   
	 * 
	 * @author Dumella De Rosa Gennaro
	 */
	public static enum Action{
		/**
		 *	<b>A</b> append a rule to the end of the selected chain. 
		 */
		A,
		/**
		 *	<b>C</b> change the counters of the specified rule or rules from the selected chain. 
		 */
		C,
		/**
		 *	<b>D</b> delete the specified rule or rules from the selected chain by specifying the complete rule as it would have been specified when it was added. Only the first encountered rule that is the same as this specified rule, in other words the matching rule with the lowest (positive) rule number, is deleted.  
		 */
		D,
		/**
		 *	<b>I</b> insert the specified rule into the selected chain at the specified rule number.  
		 */
		I
	};
	/**
	 * Each set of rules is called a chain. Each chain is an ordered list of rules that can match Ethernet frames. If a rule matches an Ethernet frame, then a processing specification tells what to do with that matching frame. The processing specification is called a 'target'. However, if the frame does not match the current rule in the chain, then the next rule in the chain is examined and so forth. Default chain are: {@link Chain#INPUT}, {@link Chain#OUTPUT}, {@link Chain#FORWARD}, {@link Chain#PREROUTING}, {@link Chain#POSTROUTING}, {@link Chain#BROUTING}. 
	 * 
	 * @author Dumella De Rosa Gennaro
	 */
	public static enum Chain{
		/**
		 *	<b>INPUT</b> in {@link Table#filter}: for frames destined for the bridge itself, on the level of the MAC destination address.  
		 */
		INPUT,
		/**
		 *	<b>OUTPUT</b> in {@link Table#filter}: for locally-generated or (b)routed frames; in {@link Table#nat} for altering locally generated or (b)routed frames before they are bridged.   
		 */
		OUTPUT,
		/**
		 *	<b>FORWARD</b> in {@link Table#filter}: for frames being forwarded by the bridge
		 */
		FORWARD,
		/**
		 *	<b>PREROUTING</b> in {@link Table#nat}: for altering frames as soon as they come in 
		 */
		PREROUTING,
		/**
		 *	<b>POSTROUTING</b> in {@link Table#nat}: for altering frames as they are about to go out.  
		 */
		POSTROUTING,
		/**
		 *	<b>BROUTING</b> in {@link Table#broute}: for making a brouter. The BROUTING chain is traversed very early.
		 */
		BROUTING
		};
	/**
	 * If a rule matches an Ethernet frame, then a processing specification tells what to do with that matching frame. The processing specification is called a 'target'. This is one of the following values: {@link Target#ACCEPT}, {@link Target#DROP}, {@link Target#CONTINUE}, {@link Target#RETURN}. 
	 * 
	 * @author Dumella De Rosa Gennaro
	 */
	public static enum Target{
		/**
		 *	<b>ACCEPT</b> means to let the frame through. In {@link Chain#BROUTING} chain however, the ACCEPT means the frame has to be bridged.
		 */
		ACCEPT,
		/**
		 *	<b>ACCEPT</b> means the frame has to be dropped. In {@link Chain#BROUTING} chain however, the DROP means the frame has to be routed.
		 */
		DROP,
		/**
		 *	<b>CONTINUE</b> means the next rule has to be checked. This can be handy, f.e., to know how many frames pass a certain point in the chain, to log those frames or to apply multiple targets on a frame.
		 */
		CONTINUE,
		/**
		 *	<b>RETURN</b> means stop traversing this chain and resume at the next rule in the previous (calling) chain.
		 */
		RETURN
	};
	
	/**
	 * Metodo statico per la generazione dei comandi ebtables.
	 * 
	 * @param table - The {@link Table} of rule.  
	 * @param action - The {@link Action} of rule.
	 * @param chain - The {@link Chain} of rule.
	 * @param in_interface - The interface (bridge port) via which a frame is received  (this option is useful in the {@link Chain#INPUT}, {@link Chain#FORWARD}, {@link Chain#PREROUTING}, and {@link Chain#BROUTING}).
	 * @param out_interface - The interface (bridge port) via which a frame is going to be sent (this option is useful in the {@link Chain#OUTPUT}, {@link Chain#FORWARD}, {@link Chain#POSTROUTING}).
	 * @param source - The source MAC address.
	 * @param destination - The destination MAC address.
	 * @param among_dst - Compare the MAC destination to the given list.
	 * @param dst_negate - If true a "!" option before the specification inverts the test.
	 * @param among_src - Compare the MAC source to the given list.
	 * @param src_negate - If true a "!" option before the specification inverts the test.
	 * @param target - The {@link Target} of rule.
	 *  
	 * @return The Ebtables command as a {@link String}
	 */
	public static String toString(Table table,Action action,Chain chain,
									String in_interface,String out_interface,
									MacAddress source,MacAddress destination,
									String among_dst,boolean dst_negate,
									String among_src,boolean src_negate,
									Target target){

			String command = "";
			
			command += "ebtables -t " + table.name() + " -" + action.name() + " " + chain.name();
			
			
			if (in_interface!=null)
				command += " -i " + in_interface;
			if (out_interface!=null)
				command += " -o " + out_interface;
			
			if(source!=null)
				command += " -s " + source.toString();
			if(destination !=(null))
				command += " -d " + destination.toString();
			
			if(among_dst!=null && !dst_negate)
				command += " --among-dst " + among_dst;
			else if(among_dst!=null && dst_negate)
				command += " --among-dst ! " + among_dst;
			
			if(among_src!=null && !src_negate)
				command += " --among-src " + among_src;
			else if(among_src!=null && src_negate)
				command += " --among-src ! " + among_src;
			
			command += " -j " + target.name();
			
			return command;
		}
	
	public static void main(String[] args) throws MacAddressException {
		
		System.out.println(
				Ebtables.toString(Table.filter, Action.A, Chain.FORWARD, "id01eth1", null, 
								new MacAddress("00:11:22:33:44:55"), null, "pippo", false, null,
								true, Target.ACCEPT)
							);
		System.out.println(
				Ebtables.toString(Table.nat, Action.A, Chain.POSTROUTING, null, "id01eth1", 
								null, null, null, true, "pippo",
								true, Target.DROP)
							);		
	}
}